package com.jsg.sl651.manager;

import com.jsg.sl651.entity.frame.header.PacketInfo;
import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;

/**
 * 消息分包管理器
 */
@Slf4j
public final class SubcontractingMessageManager {

    public static final Map<String, Map<Integer, byte[]>> SUBCONTRACTING_MESSAGE = new HashMap<>();
    public static final Map<String, PacketInfo> PACKET_INFO = new HashMap<>();

    public static synchronized void addMessage(String remoteTelemetryStationAddress, int functionCode, PacketInfo packetInfo, byte[] data) {
        String key = getKey(remoteTelemetryStationAddress, functionCode);
        PACKET_INFO.put(key, packetInfo);
        if (SUBCONTRACTING_MESSAGE.containsKey(key)) {
            SUBCONTRACTING_MESSAGE.get(key).put(packetInfo.getPacketNumber(), data);
        } else {
            Map<Integer, byte[]> map = new HashMap<>();
            map.put(packetInfo.getPacketNumber(), data);
            SUBCONTRACTING_MESSAGE.put(key, map);
        }
    }


    /**
     * 校验分包消息是否完整
     * @param remoteTelemetryStationAddress 遥测站地址HEX码
     * @param functionCode 功能码
     * @return 是否完整
     */
    public synchronized static boolean validMessage(String remoteTelemetryStationAddress, int functionCode) {
        String key = getKey(remoteTelemetryStationAddress, functionCode);
        if (!SUBCONTRACTING_MESSAGE.containsKey(key) || !PACKET_INFO.containsKey(key)) {
            return false;
        }
        PacketInfo packetInfo = PACKET_INFO.get(key);
        Map<Integer, byte[]> integerMap = SUBCONTRACTING_MESSAGE.get(key);
        return packetInfo.getTotalNumber() == integerMap.size();
    }

    /**
     * 当校验包不完整时，获取缺少的包序号
     * @param remoteTelemetryStationAddress 遥测站地址HEX码
     * @param functionCode 功能码
     * @return 是否完整
     */
    public static synchronized int[] getMissingPackerNumbers(String remoteTelemetryStationAddress, int functionCode) {
        String key = getKey(remoteTelemetryStationAddress, functionCode);
        PacketInfo packetInfo = PACKET_INFO.get(key);
        Map<Integer, byte[]> integerMap = SUBCONTRACTING_MESSAGE.get(key);
        if (packetInfo.getTotalNumber() == integerMap.size()) {
            return null;
        }
        int[] missingPackerNumbers = new int[packetInfo.getTotalNumber() - integerMap.size()];
        int index = 0;
        for (int i = 0; i < packetInfo.getTotalNumber(); i++) {
            if (!integerMap.containsKey(i)) {
                missingPackerNumbers[index++] = i;
            }
        }
        return missingPackerNumbers;
    }

    /**
     * 获取合并后的完整消息
     * <p>该方法的核心功能是从分包消息中提取并合并所有分包数据，形成完整的消息字节数组。</p>
     * <ul>
     *     <li>首先根据遥测站地址和功能码生成唯一的键。</li>
     *     <li>从 {@link #SUBCONTRACTING_MESSAGE} 和 {@link #PACKET_INFO} 中移除并获取相应的分包数据和包信息。</li>
     *     <li>如果分包数据或包信息为空，则返回一个空的字节数组（或根据业务需求抛出异常）。</li>
     *     <li>计算所有分包数据的总字节数。</li>
     *     <li>创建一个固定大小的字节数组来存储合并后的数据。</li>
     *     <li>遍历所有分包数据，使用 {@link System#arraycopy} 方法将每个分包数据复制到结果数组中。</li>
     *     <li>返回合并后的完整消息字节数组。</li>
     * </ul>
     *
     * @param remoteTelemetryStationAddress 遥测站地址HEX码
     * @param functionCode 功能码
     * @return 合并后的完整消息字节数组
     * @throws IllegalArgumentException 如果分包数据或包信息为空（根据业务需求决定是否抛出异常）
     */
    public static synchronized byte[] getMessage(String remoteTelemetryStationAddress, int functionCode) {
        String key = getKey(remoteTelemetryStationAddress, functionCode);
        Map<Integer, byte[]> datas = SUBCONTRACTING_MESSAGE.remove(key);
        PacketInfo packetInfo = PACKET_INFO.remove(key);
        if (datas == null || packetInfo == null) {
            return new byte[0]; // 或者抛出异常，根据业务需求决定
        }
        int totalNumber = packetInfo.getTotalNumber();
        int totalLength = 0;
        // 计算总字节数
        for (int i = 0; i < totalNumber; i++) {
            byte[] bytes1 = datas.get(i);
            if (bytes1 != null) {
                totalLength += bytes1.length;
            }
        }
        byte[] result = new byte[totalLength];
        int index = 0;
        // 合并分包数据
        for (int i = 0; i < totalNumber; i++) {
            byte[] bytes1 = datas.get(i);
            if (bytes1 != null) {
                System.arraycopy(bytes1, 0, result, index, bytes1.length);
                index += bytes1.length;
            }
        }
        return result;
    }



    private static String getKey(String remoteTelemetryStationAddress, int functionCode) {
        return remoteTelemetryStationAddress + Integer.toHexString(functionCode).toUpperCase();
    }

}
